package org.yecq.tradedata.service;

import com.jhhc.baseframework.data.record.SqlOperator;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.yecq.tradedata.bean.FuturesDayKLineBean;
import org.yecq.tradedata.craw.FuturesCrawler;
import org.yecq.tradedata.save.FuturesSaver;

/**
 * 期货数据抓取和保存业务
 *
 * @author yecq
 */
@Service
public class FuturesService {

    private static final Logger log = Logger.getLogger(FuturesService.class);

    @Autowired
    private FuturesCrawler craw;

    @Autowired
    private FuturesSaver saver;

    @Autowired
    private SqlOperator sql;

    @Autowired
    private BollService boll;

    // 存入期货连续合约
    public void initFuturesCode() {
        final String[] codes = new String[]{
            // 上海期货
            "CU0,铜,上海期货",
            "AL0,铝,上海期货",
            "ZN0,锌,上海期货",
            "PB0,铅,上海期货",
            "AU0,金,上海期货",
            "AG0,白银,上海期货",
            "RB0,螺纹钢,上海期货",
            "WR0,线材,上海期货",
            "FU0,燃料油,上海期货",
            "RU0,橡胶,上海期货",
            // 大连商品
            "M0,豆粕,大连商品",
            "Y0,豆油,大连商品",
            "A0,豆一,大连商品",
            "P0,棕榈油,大连商品",
            "C0,玉米,大连商品",
            "CS0,淀粉,大连商品",
            "JD0,鸡蛋,大连商品",
            "BB0,胶合板,大连商品",
            "FB0,纤维板,大连商品",
            "L0,聚乙烯,大连商品",
            "V0,PVC,大连商品",
            "PP0,聚丙烯,大连商品",
            "J0,焦炭,大连商品",
            "JM0,焦煤,大连商品",
            "I0,铁矿石,大连商品",
            // 郑州商品
            "SR0,白糖,郑州商品",
            "CF0,棉花,郑州商品",
            "CY0,棉纱,郑州商品",
            "ZC0,动力煤,郑州商品",
            "FG0,玻璃,郑州商品",
            "TA0,PTA,郑州商品",
            "MA0,甲醇,郑州商品",
            "OI0,菜油,郑州商品",
            "RM0,菜粕,郑州商品",
            "SF0,硅铁,郑州商品",
            "AP0,苹果,郑州商品",};

        for (String str : codes) {
            String[] tmp = str.split(",");
            String code = tmp[0].toUpperCase();
            String name = tmp[1];
            String exchg = tmp[2];

            this.saver.saveOrUpdateContract(code, name, exchg);
        }
    }

    // 获取并保存期货历史数据，直到目前,并存入数据库
    public void getAndSaveHistoryDatas(String code) {
        try {
            log.info("====> 获取" + code + "的所有历史交易数据");
            List<FuturesDayKLineBean> list = this.craw.getHistoryDayKLines(code);
            log.info("====> 保存" + code + "历史交易数据 ...");
            this.saver.saveOrUpdateList(list);
        } catch (Exception ex) {
            log.error(ex.getMessage());
        }
    }

    // 获取并保存目前所有的连续品种的历史数据
    public void getAndSaveHistoryDatasOfCode0() {
        List<String> code0_list = getAllCode0();
        for (String code : code0_list) {
            log.info("====> 生成" + code + "的boll值 ...");
            getAndSaveHistoryDatas(code);
        }
    }

    // 获取当前所有的品种列表
    private List<String> getAllCode0() {
        List<Map<String, Object>> tmp = this.sql.query("select code from futures order by exchg_id,code");
        List<String> list = new ArrayList(tmp.size());
        for (Map<String, Object> item : tmp) {
            list.add(item.get("code") + "");
        }

        return list;
    }

    // 获取今天的数据，并存入数据库，时间在晚上重新开盘前抓取
    public void getAndSaveTodayData(String code) {
        try {
            log.info("====> 获取和保存" + code + "的今天的最新交易数据");
            FuturesDayKLineBean bean = this.craw.getTodayDayKLine(code);
            this.saver.saveOrUpdateSingle(bean);

            // 生成当天的boll数据
            log.info("====> 生成" + code + "的今天的boll值");
            this.boll.reComputeDateAndAfter(bean.getCode(), bean.getDate());

        } catch (Exception ex) {
            log.error(ex.getMessage());
        }
    }

    // 更新所有品种的连续数据
    public void getAndSaveTodayOfCode0() {
        List<String> code0_list = getAllCode0();
        for (String code : code0_list) {
            getAndSaveTodayData(code);
            // 时间别太快
            wait4AWhile(1);
        }
    }

    // 删除非交易日的K线数据
    public void clearExceptionDateOfCode0() {
        int len = this.saver.clearDataOfExceptionDate();
        log.info("====> 清除了" + len + "条非交易日数据");
    }

    // 停一下
    private void wait4AWhile(int second) {
        try {
            Thread.sleep((long) (second * 100));
        } catch (InterruptedException ex) {
            java.util.logging.Logger.getLogger(FuturesService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    // 根据历史数据，修改某一天错误的数据
    public void updateSingleByDate(String code, String date) {
        // 获取原来的数据
        Map<String, Object> origin = getInfoByCode0Date(code, date);
        if (origin == null) {
            log.info("不存在" + code + "的在" + date + "的交易数据");
            return;
        }
        List<FuturesDayKLineBean> list = this.craw.getHistoryDayKLines(code);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (FuturesDayKLineBean bean : list) {
            try {
                Date new_date = sdf.parse(bean.getDate());
                Date old_date = sdf.parse(origin.get("date") + "");
                if (new_date.equals(old_date)) {
                    String id = origin.get("id") + "";
                    modifyInfo(id, bean.getOpen(), bean.getClose(), bean.getHigh(), bean.getLow(), bean.getVol());
                    log.info("====> " + code + "在" + date + "的记录修改为新的数据");
                }
            } catch (ParseException ex) {
                throw new IllegalStateException(ex.getMessage());
            }
        }
        // 修改boll值
        log.info("====> 生成" + code + "在" + date + "的boll值");
        this.boll.reComputeDateAndAfter(code, date);
    }

    // 一般错都是一起错，修改某一天所有品种的数据
    public void updateAllByDate(String date) {
        List<String> code0_list = getAllCode0();
        for (String code : code0_list) {
            updateSingleByDate(code, date);
            // 时间别太快
            wait4AWhile(1);
        }
    }

    // 获取某一天的数据
    private Map<String, Object> getInfoByCode0Date(String code, String date) {
        List<Map<String, Object>> list = this.sql.query("select * from futures_day_kline where date = ? and futures_id=(select id from futures where code = ?)", date, code);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    // 修改数据
    private void modifyInfo(String id, double open, double close, double high, double low, int vol) {
        String stmt = "update futures_day_kline set open=?,close=?,high=?,low=?,vol=? where id =?";
        this.sql.update(stmt, open, close, high, low, vol, id);
    }
}
